package com.sunlake.spring.main.model.account.service.impl;

import com.alipay.api.AlipayApiException;
import com.sunlake.spring.main.common.model.pay.dto.PayRequestDTO;
import com.sunlake.spring.main.common.model.pay.service.PayService;
import com.sunlake.spring.main.common.response.R;
import com.sunlake.spring.main.model.account.dto.AccountRechargeDTO;
import com.sunlake.spring.main.model.account.dto.FreezeBalanceDTO;
import com.sunlake.spring.main.model.account.dto.RefundToBalanceDTO;
import com.sunlake.spring.main.model.account.dto.UnfreezeBalanceDTO;
import com.sunlake.spring.main.model.account.mapper.FinancialRecordsMapper;
import com.sunlake.spring.main.model.account.mapper.RechargeBillsMapper;
import com.sunlake.spring.main.model.account.po.FinancialRecords;
import com.sunlake.spring.main.model.account.po.RechargeBills;
import com.sunlake.spring.main.model.account.service.AccountService;
import com.sunlake.spring.main.model.account.vo.AccountBalanceVO;
import com.sunlake.spring.main.model.auth.mapper.UsersMapper;
import com.sunlake.spring.main.model.auth.po.UsersPO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * @author liuhanzhi49
 */
@Service
@Slf4j
public class AccountServiceImpl implements AccountService {
    private static final int END_TIME = 90;
    @Autowired
    private UsersMapper usersMapper;
    @Autowired
    private FinancialRecordsMapper financialRecordsMapper;

    @Autowired
    private RechargeBillsMapper rechargeBillsMapper;

    @Autowired
    private PayService payService;

    @Override
    public R getAccountBalance(Long userId) {
        // 根据用户ID查询用户信息
        UsersPO userPO = usersMapper.selectByPrimaryKey(userId);
        if (userPO == null) {
            return R.error(404, "用户不存在");
        }
        BigDecimal balance = userPO.getAccountBalance();
        if (balance == null) {
            balance = BigDecimal.ZERO;
        }

        AccountBalanceVO vo = new AccountBalanceVO();
        vo.setBalance(balance.doubleValue());
        log.info("用户ID为{}的账户余额为{}", userId, balance);
        return R.ok(200, "查询成功", vo);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public R recharge(Long userId, AccountRechargeDTO rechargeDTO) {
        if (rechargeDTO == null || rechargeDTO.getAmount() == null || rechargeDTO.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
            return R.error(400, "充值金额必须大于0");
        }

        if (rechargeDTO.getPaymentMethod() == null || rechargeDTO.getPaymentMethod().isEmpty()) {
            return R.error(400, "请选择支付方式");
        }

        UsersPO userPO = usersMapper.selectByPrimaryKey(userId);
        if (userPO == null) {
            return R.error(404, "用户不存在");
        }

        try {
            BigDecimal amount = rechargeDTO.getAmount();
            BigDecimal giftAmount = calculateGiftAmount(amount);
            BigDecimal totalAmount = amount.add(giftAmount);

            PayRequestDTO payRequestDTO = new PayRequestDTO();
            payRequestDTO.setSubject("账户充值");
            payRequestDTO.setBody("用户ID：" + userId + "，充值金额：" + amount);
            payRequestDTO.setTotalAmount(amount.toString());
            payRequestDTO.setTimeoutExpress("90m");

            // 先生成支付二维码，让PayService生成outTradeNo
            payService.generatePayQrCode(payRequestDTO);

            // 获取PayService生成的outTradeNo作为最终的rechargeNo
            String finalRechargeNo = payRequestDTO.getOutTradeNo();
            if (finalRechargeNo == null || finalRechargeNo.isEmpty()) {
                // 如果获取失败，使用临时生成的充值单号
                finalRechargeNo = generateRechargeNo();
            }

            createPendingRechargeBill(userId, finalRechargeNo, amount, giftAmount, totalAmount, rechargeDTO.getPaymentMethod());

            LocalDateTime expireTime = LocalDateTime.now().plusMinutes(END_TIME);
            String expireTimeStr = expireTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

            Map<String, Object> result = new HashMap<>();
            result.put("transaction_id", null);
            result.put("recharge_no", finalRechargeNo);
            result.put("amount", amount);
            result.put("payment_url", "/api/pay?rechargeNo=" + finalRechargeNo);
            result.put("expire_time", expireTimeStr);
            log.info("生成充值订单成功：用户ID={}, 充值金额={}, 充值单号={}", userId, amount, finalRechargeNo);
            return R.ok(200, "生成支付二维码成功", result);
        } catch (AlipayApiException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public R getAccountRechargeRecords(Long userId) {
        try {
            // 注意：这里应该实现查询用户充值记录的功能
            return R.ok(200, "查询成功", "[]");
        } catch (Exception e) {
            log.error("查询用户充值记录失败：用户ID={}", userId, e);
            return R.error(500, "查询用户充值记录失败");
        }
    }

    @Override
    public R getAccountConsumptionRecords(Long userId) {
        try {
            // 注意：这里应该实现查询用户消费记录的功能
            return R.ok(200, "查询成功", "[]");
        } catch (Exception e) {
            log.error("查询用户消费记录失败：用户ID={}", userId, e);
            return R.error(500, "查询用户消费记录失败");
        }
    }

    private BigDecimal calculateGiftAmount(BigDecimal amount) {
        // 充值100以上赠送10%
        if (amount.compareTo(new BigDecimal(100)) > 0) {
            return amount.multiply(new BigDecimal("0.1"));
        }
        return BigDecimal.ZERO;
    }

    /**
     * 生成充值单号
     */
    private String generateRechargeNo() {
        return "REC" + System.currentTimeMillis() + UUID.randomUUID().toString().substring(0, 8);
    }

    /**
     * 创建待支付的充值记录
     */
    private void createPendingRechargeBill(Long userId, String rechargeNo, BigDecimal amount,
                                           BigDecimal giftAmount, BigDecimal totalAmount, String paymentMethod) {
        RechargeBills rechargeBill = new RechargeBills();
        rechargeBill.setUserId(userId.intValue());
        rechargeBill.setRechargeNo(rechargeNo);
        rechargeBill.setAmount(amount);
        rechargeBill.setGiftAmount(giftAmount);
        rechargeBill.setTotalAmount(totalAmount);
        rechargeBill.setPaymentMethod(paymentMethod);
        rechargeBill.setStatus("PENDING");
        rechargeBill.setCreatedAt(LocalDateTime.now());
        rechargeBill.setUpdatedAt(LocalDateTime.now());

        int insertResult = rechargeBillsMapper.insertSelective(rechargeBill);
        if (insertResult == 0) {
            throw new RuntimeException("创建充值记录失败");
        }
    }
    /**
     * 检查充值订单状态
     */
    @Override
    public R checkRechargeStatus(String rechargeNo) {
        if (rechargeNo == null || rechargeNo.isEmpty()) {
            return R.error(400, "充值单号不能为空");
        }

        // 根据充值单号查询充值记录
        RechargeBills rechargeBill = rechargeBillsMapper.selectByRechargeNo(rechargeNo);
        if (rechargeBill == null) {
            return R.error(404, "充值记录不存在");
        }

        // 组装返回数据
        Map<String, String> result = new HashMap<>();
        result.put("status", rechargeBill.getStatus());
        result.put("recharge_no", rechargeBill.getRechargeNo());
        result.put("amount", rechargeBill.getAmount().toString());
        log.info("检查充值订单状态：用户ID={}, 充值单号={}, 状态={}",
                rechargeBill.getUserId(), rechargeBill.getRechargeNo(), rechargeBill.getStatus());
        return R.ok(200, "查询成功", result);
    }
    /**
     * 支付成功后更新用户余额
     * 注意：该方法会在支付回调中被调用
     *
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updateBalanceAfterPayment(String rechargeNo, String transactionNo) {
        try {
            // 1. 查询充值记录
            RechargeBills rechargeBill = rechargeBillsMapper.selectByRechargeNo(rechargeNo);
            if (rechargeBill == null) {
                log.error("充值记录不存在：{}", rechargeNo);
                return false;
            }

            // 2. 检查订单状态，避免重复处理
            if (!"PENDING".equals(rechargeBill.getStatus())) {
                log.warn("订单状态异常，当前状态：{}", rechargeBill.getStatus());
                return false;
            }

            UsersPO userPO = usersMapper.selectByPrimaryKey((long) rechargeBill.getUserId());
            if (userPO == null) {
                log.error("用户不存在：{}", rechargeBill.getUserId());
                return false;
            }

            BigDecimal currentBalance = userPO.getAccountBalance() != null ? userPO.getAccountBalance() : BigDecimal.ZERO;
            BigDecimal newBalance = currentBalance.add(rechargeBill.getTotalAmount());

            int updateResult = usersMapper.updateAccountBalance((long) rechargeBill.getUserId(), newBalance);
            if (updateResult == 0) {
                log.error("更新用户余额失败：用户ID={}", rechargeBill.getUserId());
                return false;
            }

            // 5. 更新充值记录状态
            LocalDateTime now = LocalDateTime.now();
            String nowStr = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
            rechargeBillsMapper.updateStatusByRechargeNo(
                    rechargeNo, "SUCCESS", transactionNo, nowStr, nowStr);
            FinancialRecords record = new FinancialRecords();
            record.setUserId(userPO.getId());
            record.setAmount(rechargeBill.getTotalAmount());
            record.setRecordType("RECHARGE");
            record.setRelatedNo(rechargeNo);
            record.setBalanceAfter(newBalance);
            record.setRemark("账户充值" + rechargeBill.getAmount() + "元，赠送" + rechargeBill.getGiftAmount() + "元");
            record.setCreatedAt(LocalDateTime.now());
            financialRecordsMapper.insertSelective(record);
            log.info("支付成功，更新余额完成：用户ID={}, 充值单号={}, 充值金额={}",
                    rechargeBill.getUserId(), rechargeNo, rechargeBill.getTotalAmount());
            return true;
        } catch (Exception e) {
            log.error("更新余额失败：{}", e.getMessage(), e);
            return false;
        }
    }
    @Override
    public R getAccountBalanceRecords(
            Long userId,
            String recordType,
            LocalDateTime startDate,
            LocalDateTime endDate,
            Integer page,
            Integer pageSize) {
        try {
            if (page == null || page < 1) {
                page = 1;
            }
            if (pageSize == null || pageSize < 1) {
                pageSize = 10;
            }
            // 计算偏移量
            Integer offset = (page - 1) * pageSize;

            // 查询数据
            List<FinancialRecords> records = financialRecordsMapper.selectBalanceRecords(
                    userId, recordType, startDate, endDate, offset, pageSize);
            // 查询总条数
            int total = financialRecordsMapper.countBalanceRecords(
                    userId, recordType, startDate, endDate);
            // 组装返回数据
            Map<String, Object> result = new HashMap<>();
            result.put("records", records);
            result.put("total", total);
            result.put("page", page);
            result.put("pageSize", pageSize);
            result.put("totalPages", (total + pageSize - 1) / pageSize);

            log.info("查询用户余额明细成功：用户ID={}, 记录数={}", userId, records.size());
            return R.ok(200, "查询成功", result);
        } catch (Exception e) {
            log.error("查询用户余额明细失败：用户ID={}", userId, e);
            return R.error(500, "查询用户余额明细失败");
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public R freezeBalance(Long userId, FreezeBalanceDTO freezeDTO) {
        try {
            // 1. 参数校验
            if (freezeDTO.getAmount() == null || freezeDTO.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
                return R.error(400, "冻结金额必须大于0");
            }

            if (freezeDTO.getTransactionNo() == null || freezeDTO.getTransactionNo().isEmpty()) {
                return R.error(400, "交易单号不能为空");
            }

            // 2. 查询用户信息
            UsersPO userPO = usersMapper.selectByPrimaryKey(userId);
            if (userPO == null) {
                return R.error(404, "用户不存在");
            }

            // 3. 检查余额是否足够
            BigDecimal currentBalance = userPO.getAccountBalance() != null ? userPO.getAccountBalance() : BigDecimal.ZERO;
            if (currentBalance.compareTo(freezeDTO.getAmount()) < 0) {
                return R.error(400, "可用余额不足，无法冻结");
            }

            // 4. 创建冻结记录（使用financial_records表记录冻结状态）
            FinancialRecords freezeRecord = new FinancialRecords();
            freezeRecord.setUserId(Math.toIntExact(userId));
            freezeRecord.setAmount(freezeDTO.getAmount());
            freezeRecord.setRecordType("FROZEN");
            freezeRecord.setRelatedNo(freezeDTO.getTransactionNo());
            freezeRecord.setBalanceAfter(currentBalance);
            freezeRecord.setRemark(freezeDTO.getBusinessDesc());
            freezeRecord.setCreatedAt(LocalDateTime.now());

            financialRecordsMapper.insertSelective(freezeRecord);

            // 5. 返回结果
            Map<String, Object> result = new HashMap<>();
            result.put("frozen_amount", freezeDTO.getAmount());
            result.put("available_balance", currentBalance.subtract(freezeDTO.getAmount()));
            result.put("frozen_balance", freezeDTO.getAmount()); // 这里仅返回本次冻结金额

            log.info("用户ID={} 冻结余额成功，金额={}, 交易单号={}", userId, freezeDTO.getAmount(), freezeDTO.getTransactionNo());
            return R.ok(200, "余额冻结成功", result);
        } catch (Exception e) {
            log.error("冻结余额失败：", e);
            return R.error(500, "冻结余额失败：" + e.getMessage());
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public R unfreezeBalance(Long userId, UnfreezeBalanceDTO unfreezeDTO) {
        try {
            if (unfreezeDTO.getTransactionNo() == null || unfreezeDTO.getTransactionNo().isEmpty()) {
                return R.error(400, "交易单号不能为空");
            }

            // 查询冻结记录
            FinancialRecords freezeRecord = financialRecordsMapper.selectByRelatedNoAndType(
                    Math.toIntExact(userId), unfreezeDTO.getTransactionNo(), "FROZEN");

            if (freezeRecord == null) {
                return R.error(404, "未找到对应的冻结记录");
            }

            // 创建解冻记录
            FinancialRecords unfreezeRecord = new FinancialRecords();
            unfreezeRecord.setUserId(Math.toIntExact(userId));
            unfreezeRecord.setAmount(freezeRecord.getAmount().negate()); // 负数表示解冻
            unfreezeRecord.setRecordType("UNFROZEN");
            unfreezeRecord.setRelatedNo(unfreezeDTO.getTransactionNo());
            unfreezeRecord.setRemark(unfreezeDTO.getBusinessDesc());
            unfreezeRecord.setCreatedAt(LocalDateTime.now());

            // 获取当前余额
            UsersPO userPO = usersMapper.selectByPrimaryKey(userId);
            BigDecimal currentBalance = userPO.getAccountBalance() != null ? userPO.getAccountBalance() : BigDecimal.ZERO;
            unfreezeRecord.setBalanceAfter(currentBalance);

            financialRecordsMapper.insertSelective(unfreezeRecord);

            // 返回结果
            Map<String, Object> result = new HashMap<>();
            result.put("unfrozen_amount", freezeRecord.getAmount());
            result.put("available_balance", currentBalance);
            result.put("frozen_balance", BigDecimal.ZERO); // 解冻后，该笔冻结金额变为0

            log.info("用户ID={} 解冻余额成功，金额={}, 交易单号={}", userId, freezeRecord.getAmount(), unfreezeDTO.getTransactionNo());
            return R.ok(200, "余额解冻成功", result);
        } catch (Exception e) {
            log.error("解冻余额失败：", e);
            return R.error(500, "解冻余额失败：" + e.getMessage());
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public R refundToBalance(Long userId, RefundToBalanceDTO refundDTO) {
        try {
            // 参数校验
            if (refundDTO.getAmount() == null || refundDTO.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
                return R.error(400, "返还金额必须大于0");
            }

            if (refundDTO.getTransactionNo() == null || refundDTO.getTransactionNo().isEmpty()) {
                return R.error(400, "退款单号不能为空");
            }

            // 查询用户信息
            UsersPO userPO = usersMapper.selectByPrimaryKey(userId);
            if (userPO == null) {
                return R.error(404, "用户不存在");
            }

            // 更新用户余额
            BigDecimal currentBalance = userPO.getAccountBalance() != null ? userPO.getAccountBalance() : BigDecimal.ZERO;
            BigDecimal newBalance = currentBalance.add(refundDTO.getAmount());

            int updateResult = usersMapper.updateAccountBalance(userId, newBalance);
            if (updateResult == 0) {
                return R.error(500, "更新用户余额失败");
            }

            // 创建退款记录
            FinancialRecords refundRecord = new FinancialRecords();
            refundRecord.setUserId(Math.toIntExact(userId));
            refundRecord.setAmount(refundDTO.getAmount());
            refundRecord.setRecordType("REFUND");
            refundRecord.setRelatedNo(refundDTO.getTransactionNo());
            refundRecord.setBalanceAfter(newBalance);
            refundRecord.setRemark(refundDTO.getBusinessDesc());
            refundRecord.setCreatedAt(LocalDateTime.now());

            financialRecordsMapper.insertSelective(refundRecord);

            // 返回结果
            Map<String, Object> result = new HashMap<>();
            result.put("refund_amount", refundDTO.getAmount());
            result.put("balance_after", newBalance);

            log.info("用户ID={} 余额返还成功，金额={}, 退款单号={}", userId, refundDTO.getAmount(), refundDTO.getTransactionNo());
            return R.ok(200, "余额返还成功", result);
        } catch (Exception e) {
            log.error("余额返还失败：", e);
            return R.error(500, "余额返还失败：" + e.getMessage());
        }
    }

    @Transactional(rollbackFor = Exception.class)
//    @Override
    public boolean payWithBalance(Long userId, String orderNo, BigDecimal amount) {
        try {
            // 查询用户信息
            UsersPO userPO = usersMapper.selectByPrimaryKey(userId);
            if (userPO == null) {
                log.error("用户不存在：{}", userId);
                return false;
            }

            // 计算可用余额（当前余额减去所有冻结金额）
            BigDecimal currentBalance = userPO.getAccountBalance() != null ? userPO.getAccountBalance() : BigDecimal.ZERO;

            // 查询该用户所有未解冻的冻结金额
            List<FinancialRecords> frozenRecords = financialRecordsMapper.selectUnfrozenByUserId(Math.toIntExact(userId));
            BigDecimal totalFrozen = frozenRecords.stream()
                    .map(FinancialRecords::getAmount)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);

            BigDecimal availableBalance = currentBalance.subtract(totalFrozen);

            // 检查余额是否足够
            if (availableBalance.compareTo(amount) < 0) {
                log.error("用户余额不足：用户ID={}, 可用余额={}, 需支付={}", userId, availableBalance, amount);
                return false;
            }

            // 更新用户余额
            BigDecimal newBalance = currentBalance.subtract(amount);
            int updateResult = usersMapper.updateAccountBalance(userId, newBalance);
            if (updateResult == 0) {
                log.error("更新用户余额失败：用户ID={}", userId);
                return false;
            }

            // 创建消费记录
            FinancialRecords consumeRecord = new FinancialRecords();
            consumeRecord.setUserId(Math.toIntExact(userId));
            consumeRecord.setAmount(amount.negate()); // 负数表示支出
            consumeRecord.setRecordType("CONSUME");
            consumeRecord.setRelatedNo(orderNo);
            consumeRecord.setBalanceAfter(newBalance);
            consumeRecord.setRemark("余额支付订单：" + orderNo);
            consumeRecord.setCreatedAt(LocalDateTime.now());

            financialRecordsMapper.insertSelective(consumeRecord);

            log.info("用户ID={} 使用余额支付成功，订单号={}, 金额={}", userId, orderNo, amount);
            return true;
        } catch (Exception e) {
            log.error("余额支付失败：", e);
            return false;
        }
    }
}